package com.qunchuang.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qunchuang.constant.LiftConstant;
import com.qunchuang.constant.LiftStorageLocationConstant;
import com.qunchuang.constant.LiftTaskStateConstant;
import com.qunchuang.mapper.*;
import com.qunchuang.pojo.dto.AgvLiftStorageLocationDto;
import com.qunchuang.pojo.entity.LiftAgvcHistoryEntity;
import com.qunchuang.pojo.entity.LiftAgvcTaskEntity;
import com.qunchuang.pojo.entity.LiftEntity;
import com.qunchuang.pojo.entity.LiftStorageLocationEntity;
import com.qunchuang.pojo.vo.ResponseVo;
import com.qunchuang.service.AgvService;
import com.qunchuang.utils.Modbus4jUtils;
import com.serotonin.modbus4j.code.DataType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AgvServiceImpl implements AgvService {
    @Autowired
    private LiftMapper liftMapper;
    @Autowired
    private LiftAgvcTaskMapper liftAgvcTaskMapper;
    @Autowired
    private PointsMapper pointsMapper;
    @Autowired
    private LiftStorageLocationMapper liftStorageLocationMapper;
    @Autowired
    private LiftAgvcHistoryMapper liftAgvcHistoryMapper;
    /**
     * agv到达电梯储位
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseVo agvArriveStorageLocation(AgvLiftStorageLocationDto dto){
        String agvId = dto.getAgvId();
        String liftCode = dto.getLiftCode();
        String storagePoint = dto.getStoragePoint();
        ResponseVo responseVo = new ResponseVo();
        responseVo.setReturnCode(1);
        //查询任务表
        Integer id = getLiftAgvTaskId(liftCode, agvId, storagePoint);
        //判断任务大小
            //修改任务表状态为5
        Integer i = updateLiftAavTastState(id, LiftTaskStateConstant.LIFT_DOOR_COMPLETELY_OPEN);
        ifUpdateSucceed(i,"修改电梯任务表成功，状态为3","修改电梯任务表失败，进行回滚");
        return responseVo;

//        responseVo.setReturnCode(-1);
//        responseVo.setReturnReason("agv储位失败");
//        return responseVo;
    }

//    {
//        String agvId = dto.getAgvId();
//        String liftCode = dto.getLiftCode();
//        String storagePoint = dto.getStoragePoint();
//        ResponseVo responseVo = new ResponseVo();
//        responseVo.setReturnCode(1);
//        //查询任务表
//        QueryWrapper<LiftAgvcTaskEntity> liftAgvcTaskEntityQueryWrapper = new QueryWrapper<>();
//        liftAgvcTaskEntityQueryWrapper.eq("lift_id",liftCode);
//        liftAgvcTaskEntityQueryWrapper.eq("storage_location_id",storagePoint);
//        liftAgvcTaskEntityQueryWrapper.eq("agv_id",agvId);
//        LiftAgvcTaskEntity liftAgvTaskEntity = liftAgvcTaskMapper.selectOne(liftAgvcTaskEntityQueryWrapper);
//        //查询任务大小
//        QueryWrapper<LiftAgvcTaskEntity> wrapper = new QueryWrapper<>();
//        wrapper.eq("lift_id",liftCode);
//        wrapper.eq("lift_start_floor",liftAgvTaskEntity.getLiftStartFloor());
//        wrapper.eq("lift_end_floor",liftAgvTaskEntity.getLiftEndFloor());
//        Long liftTaskCount = liftAgvcTaskMapper.selectCount(wrapper);
//
//
//        QueryWrapper<LiftAgvcTaskEntity> entityQueryWrapper = new QueryWrapper<>();
//        entityQueryWrapper.eq("lift_id",liftCode);
//        List<LiftAgvcTaskEntity> liftAgvcTaskEntities = liftAgvcTaskMapper.selectList(entityQueryWrapper);
//        Integer id = getLiftAgvTaskId(liftCode, agvId, storagePoint);
//        //判断任务大小
//        if (liftTaskCount == 2 || liftTaskCount >2){
//            boolean flag = false;
//            //大小为2，等待agv全到达电梯储位执行任务
//            List<String> storageLocationIds = liftAgvcTaskEntities.stream().map(LiftAgvcTaskEntity::getStorageLocationId).distinct().collect(Collectors.toList());
//            while (!flag){
//                //TODO 等待多久时间，没有到怎么办？一直等待？
//                QueryWrapper<LiftStorageLocationEntity> liftStorageLocationEntityQueryWrapper = new QueryWrapper<>();
//                liftStorageLocationEntityQueryWrapper.eq("storage_state", LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_UNAVAILABLE);
//                liftStorageLocationEntityQueryWrapper.in("storage_location_id",storageLocationIds);
//                Long AgvArriveSize = liftStorageLocationMapper.selectCount(liftStorageLocationEntityQueryWrapper);
//                if (AgvArriveSize ==2){
//
//                    flag =true;
//                }
//                Thread.sleep(1000);
//            }
//            //修改任务表状态为5
//            updateLiftAavTastState(id,LiftTaskStateConstant.LIFT_DOOR_COMPLETELY_OPEN);
//            return responseVo;
//        }else if (liftTaskCount == 1){
//            //TODO 等待时间不确定
//            Thread.sleep(10000);
//            //大小为1，等待一定时间后执行任务
//
//            updateLiftAavTastState(id,LiftTaskStateConstant.LIFT_DOOR_COMPLETELY_OPEN);
//            return responseVo;
//        }
//        responseVo.setReturnCode(-1);
//        responseVo.setReturnReason("agv储位失败");
//        return responseVo;
//    }

    /**
     * agv离开电梯，释放电梯
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseVo agvLeaveLift(AgvLiftStorageLocationDto dto){
        String agvId = dto.getAgvId();
        String liftCode = dto.getLiftCode();
        String storagePoint = dto.getStoragePoint();
        ResponseVo responseVo = new ResponseVo();
        responseVo.setReturnCode(1);
        //修改储位表
        LiftStorageLocationEntity liftStorageLocationEntity = new LiftStorageLocationEntity();
        liftStorageLocationEntity.setStorageState(LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_FREE);
        liftStorageLocationEntity.setAgvId("");
        QueryWrapper<LiftStorageLocationEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("storage_location_id",storagePoint);
        int update = liftStorageLocationMapper.update(liftStorageLocationEntity, queryWrapper);
        ifUpdateSucceed(update,"修改电梯储位表成功,电梯空闲，agv为空","修改电梯储位表失败，进行回滚");

        //查询电梯中有几个agv
//        Long liftStorageLocationEntityCount = selectliftStorageLocationEntityCount(liftCode,LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_UNAVAILABLE);
//        boolean flag = false;
//        if (liftStorageLocationEntityCount == 1){
//            while (!flag){
//                Long locationEntityCount = selectliftStorageLocationEntityCount(liftCode, LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_UNAVAILABLE);
//                if (locationEntityCount == 0){
//                    flag =true;
//                }
//                Thread.sleep(1000);
//            }
//        }
        QueryWrapper<LiftAgvcTaskEntity> liftAgvcTaskEntityQueryWrapper = new QueryWrapper<>();
        liftAgvcTaskEntityQueryWrapper.eq("lift_id",liftCode);
        liftAgvcTaskEntityQueryWrapper.eq("agv_id",agvId);
        liftAgvcTaskEntityQueryWrapper.eq("storage_location_id",storagePoint);
        LiftAgvcTaskEntity liftAgvcTaskEntity = liftAgvcTaskMapper.selectOne(liftAgvcTaskEntityQueryWrapper);
        Integer id = liftAgvcTaskEntity.getId();
        //修改任务表状态
        Integer i = updateLiftAavTastState(id, LiftTaskStateConstant.LIFT_DOOR_COMPLETELY_CLOSED);
        ifUpdateSucceed(i,"修改电梯任务表成功，状态为6","修改电梯任务表失败，进行回滚");
        return responseVo;
    }

    //agv异常强制释放电梯
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseVo compulsionReleaseLift(AgvLiftStorageLocationDto dto) throws Exception{
        ResponseVo responseVo = new ResponseVo();
        responseVo.setReturnCode(1);
        //agvID
        String agvId = dto.getAgvId();
        //电梯号
        String liftCode = dto.getLiftCode();
        //电梯储位
        String storagePoint = dto.getStoragePoint();
        QueryWrapper<LiftAgvcTaskEntity> liftAgvcTaskEntityQueryWrapper = new QueryWrapper<>();
        liftAgvcTaskEntityQueryWrapper.eq("agv_id",agvId);
        liftAgvcTaskEntityQueryWrapper.eq("lift_id",liftCode);
        liftAgvcTaskEntityQueryWrapper.eq("storage_id",storagePoint);
        LiftAgvcTaskEntity liftAgvcTaskEntity = liftAgvcTaskMapper.selectOne(liftAgvcTaskEntityQueryWrapper);
        Integer id = liftAgvcTaskEntity.getId();
        LiftAgvcHistoryEntity liftAgvcHistoryEntity = new LiftAgvcHistoryEntity();
        BeanUtils.copyProperties(liftAgvcTaskEntity,liftAgvcHistoryEntity);
        liftAgvcHistoryMapper.insert(liftAgvcHistoryEntity);
        liftAgvcTaskMapper.deleteById(id);
        //修改储位表
        LiftStorageLocationEntity liftStorageLocationEntity = new LiftStorageLocationEntity();
        liftStorageLocationEntity.setStorageState(LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_FREE);
        liftStorageLocationEntity.setAgvId("");
        QueryWrapper<LiftStorageLocationEntity> liftStorageLocationEntityQueryWrapper = new QueryWrapper<>();
        liftStorageLocationEntityQueryWrapper.eq("storage_location_id",storagePoint);
        int update = liftStorageLocationMapper.update(liftStorageLocationEntity, liftStorageLocationEntityQueryWrapper);
        ifUpdateSucceed(update,"agv异常，强制释放电梯储位","agv异常，强制释放电梯储位失败，进行回滚操作");
        //查询电梯中有几条任务
        QueryWrapper<LiftStorageLocationEntity> storageLocationEntityQueryWrapper = new QueryWrapper<>();
        storageLocationEntityQueryWrapper.eq("lift_id",liftCode);
        storageLocationEntityQueryWrapper.eq("storage_state",LiftStorageLocationConstant.LIFT_STORAGE_LOCATION_UNAVAILABLE);
        Long liftStorageLocationCount = liftStorageLocationMapper.selectCount(storageLocationEntityQueryWrapper);

        if (liftStorageLocationCount == 0){
            //查询电梯表
            QueryWrapper<LiftEntity> liftEntityQueryWrapper = new QueryWrapper<>();
            liftEntityQueryWrapper.eq("lift_id",liftCode);
            LiftEntity selectLift = liftMapper.selectOne(liftEntityQueryWrapper);
            String ip = selectLift.getLiftIp();
            Integer port = selectLift.getLiftPort();
            //电梯储位为空，电梯空闲
            //todo 通过modbus来读取电梯所在楼层写入电梯表
            Number number = Modbus4jUtils.readHoldingRegister(ip, port, 1, 4, DataType.TWO_BYTE_INT_SIGNED);
            int liftRemainFloor = number.intValue();
            LiftEntity liftEntity = new LiftEntity();
            liftEntity.setLiftRemainFloor(liftRemainFloor);
            liftEntity.setLiftState(LiftConstant.LIFT_STATE_IDLE);
            QueryWrapper<LiftEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("lift_id",liftCode);
            int update1 = liftMapper.update(liftEntity, queryWrapper);
            ifUpdateSucceed(update1,"agv异常，修改电梯表成功","agv异常，修改电梯表失败，进行回滚操作");
            return responseVo;
        }
        return responseVo;
    }

    private Long selectliftStorageLocationEntityCount(String liftCode,Integer storageState) {
        QueryWrapper<LiftStorageLocationEntity> liftStorageLocationEntityQueryWrapper = new QueryWrapper<>();
        liftStorageLocationEntityQueryWrapper.eq("lift_id", liftCode);
        liftStorageLocationEntityQueryWrapper.eq("storage_state",storageState);
        Long liftStorageLocationEntityCount = liftStorageLocationMapper.selectCount(liftStorageLocationEntityQueryWrapper);
        return liftStorageLocationEntityCount;
    }

    private Integer getLiftAgvTaskId(String liftCode, String agvId, String storagePoint) {
        QueryWrapper<LiftAgvcTaskEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("lift_id", liftCode);
        queryWrapper.eq("agv_id", agvId);
        queryWrapper.eq("storage_location_id", storagePoint);
        LiftAgvcTaskEntity liftAgvcTaskEntity = liftAgvcTaskMapper.selectOne(queryWrapper);
        Integer id = liftAgvcTaskEntity.getId();
        return id;
    }

    private Integer updateLiftAavTastState( Integer id,Integer state) {
        LiftAgvcTaskEntity liftAgvTaskEntity = new LiftAgvcTaskEntity();
        liftAgvTaskEntity.setState(state);
        QueryWrapper<LiftAgvcTaskEntity> TaskEntityQueryWrapper = new QueryWrapper<>();
        TaskEntityQueryWrapper.eq("id", id);
        int update = liftAgvcTaskMapper.update(liftAgvTaskEntity, TaskEntityQueryWrapper);
        return update;
    }
    private static void ifUpdateSucceed(Integer i,String succeed, String fail) {
        if (i > 0){
            log.info(succeed);
        }else {
            throw new RuntimeException(fail);
        }
    }
}
